package controllers

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math"
	"os"
	"strconv"
	"time"
	"translate_backend/db"
	"translate_backend/models"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

// M Map的简写
type M map[string]interface{}

type BaseController struct {

	//services.Service
}

//===============CRUD操作==============

// 根据id获取一个对象,只能用于GET请求
// @limitFields:限制要显示的fields
func (baseController *BaseController) GetObjectByID(col string, limitFields map[string]int, c *gin.Context) {

	oid := c.Param("id") //:id 要匹配路由里面的命名
	if oid == "" {
		baseController.ServeError(404, "", nil, c)
	} else {

		var eo map[string]interface{}
		db.FindOne(oid, col, limitFields, &eo)

		//由于golang 空对象也有值,所以需要判断长度
		if eo["id"] == "" {
			baseController.ServeError(404, "", nil, c)
		} else {

			baseController.ServeSuccess(eo, "", c)
		}

	}

}

// 分页获取
func (baseController *BaseController) GetAllByPage(col string, queryMap map[string]interface{}, limitFields map[string]int, sortKeys []string, c *gin.Context) {

	var res []interface{}
	//var res []models.LangItem
	count := 0

	//只支持get , json格式的post , 以及form 形式
	page := 0
	pagesize := 0
	if c.Request.Method == "GET" {
		page, _ = strconv.Atoi(c.DefaultQuery("page", "1"))
		pagesize, _ = strconv.Atoi(c.DefaultQuery("pagesize", "500"))
	} else {
		// json post
		var pageItem models.PageModel
		_ = c.ShouldBindJSON(&pageItem)

		page = pageItem.Page
		pagesize = pageItem.Pagesize

		//form
		if pg := c.GetInt("page"); pg > 0 {
			page = pg
		}

		if pgz := c.GetInt("pagesize"); pgz > 0 {
			pagesize = pgz
		}
	}

	//fmt.Println("page:", page, "pagesize:", pagesize)

	// fmt.Println("mpageSize:", mpageSize)

	// fmt.Println("fpageSize:", fpageSize)

	//(从1开始)
	page = int(math.Max(1.0, float64(page)))
	//每页最多显示500条
	pagesize = int(math.Min(500.0, float64(pagesize)))
	//每页最少显示1条
	pagesize = int(math.Max(1.0, float64(pagesize)))

	fmt.Println("pages信息:", page, pagesize)

	//按时间倒序排
	if sortKeys == nil {
		sortKeys = []string{"-createDate"}
	}

	//默认忽略ID
	if limitFields == nil {

		limitFields = map[string]int{"_id": 0}
	}

	count = db.FindByPage(col, page, pagesize, queryMap, limitFields, sortKeys, &res, true)

	totalPage := count / pagesize

	if count%pagesize > 0 {
		totalPage = totalPage + 1
	}

	//fmt.Println("条数:", count, "data:", res)
	baseController.ServeSuccessWithPaging(res, page, pagesize, totalPage, count, "", c)

}

// 更新一个对象 参数为表名 POST请求
func (baseController *BaseController) UpdateObjectByID(col string, c *gin.Context) {

	var paraData map[string]interface{}

	if err := c.ShouldBindBodyWith(&paraData, binding.JSON); err != nil {
		baseController.ServeError(402, "参数获取失败,json序列化错误", nil, c)
		return
	}
	fmt.Println("参数:", paraData)

	oid := paraData["id"]
	fmt.Println("id:", oid)
	//没有id
	if oid == nil || oid == "" {
		baseController.ServeError(403, "item id为空", nil, c)
	} else {
		res := db.UpdateOne(oid.(string), col, paraData)

		if res {
			baseController.ServeSuccess(nil, "更新成功", c)
		} else {
			baseController.ServeError(404, "", nil, c)
		}
	}

}

// 删除一个对象 参数为表名 一定是POST请求
func (baseController *BaseController) DeleteObjectByID(col string, c *gin.Context) {

	var m models.BaseModel
	if err := c.ShouldBindBodyWith(&m, binding.JSON); err != nil {
		baseController.ServeError(403, "参数获取失败,json序列化错误", nil, c)
		println("111111111111111111111")
		return
	}
	println("222222222222222")
	res := db.DeleteOne(m.ID, col)

	if res {
		baseController.ServeSuccess(m.ID, "", c)
		println("3333333333333333")
	} else {
		println("444444444444")
		baseController.ServeError(403, "删除失败", nil, c)
	}

}

//===============服务器返回==============

// ServeError 服务器异常返回.
func (baseController *BaseController) ServeError(errCode int, errMsg string, data interface{}, c *gin.Context) {

	mErrMsg := errMsg
	if errMsg == "" {

		mErrMsg = "该资源不存在"

		switch errCode {
		case 400:
			mErrMsg = "未知错误"
		case 401:
			mErrMsg = "授权错误"
		case 403:
			mErrMsg = "参数错误"
		case 404:
			mErrMsg = "该资源不存在"
		case 500:
			mErrMsg = "服务器错误"

		}

	}

	c.JSON(errCode, gin.H{
		"msg":       mErrMsg,
		"errorCode": errCode,
		"data":      data})
}

// ServeSuccess 服务器成功返回数据.
func (baseController *BaseController) ServeSuccess(entity interface{}, sMsg string, c *gin.Context) {

	successMsg := sMsg
	if sMsg == "" {
		successMsg = "ok"
	}

	c.JSON(200, gin.H{
		"msg":       successMsg,
		"errorCode": 0,
		"data":      entity})
}

func (baseController *BaseController) ServeSuccessWithPaging(entity interface{}, page int, pagesize int, totalPage int, itemCount int, sMsg string, c *gin.Context) {

	successMsg := sMsg
	if sMsg == "" {
		successMsg = "ok"
	}

	c.JSON(200, gin.H{
		"msg":       successMsg,
		"errorCode": 0,
		"page":      page,
		"pagesize":  pagesize,
		"totalPage": totalPage,
		"itemCount": itemCount,
		"data":      entity})
}

// 创建zip流
func AddZip(zipW *zip.Writer, filename string, content string) error {

	f, err := zipW.Create(filename)
	if err != nil {
		println(" 创建压缩文件失败:", filename)
		return err
	}
	_, err = f.Write([]byte(content))
	if err != nil {
		println(" 写入压缩文件失败:", filename)
		return err
	}

	return nil
}

//压缩目录
//files 文件数组，可以是不同dir下的文件或者文件夹
// func Compress(files []*os.File,zipW *zip.Writer) error {

// 	for _, file := range files {
// 		err := compress(file, "", zipW)
// 		if err != nil {
// 			println("压缩出错",err)
// 			return err
// 		}
// 	}
// 	return nil
// }

// 压缩目录
// files 文件数组，可以是不同dir下的文件或者文件夹
// dest 压缩文件存放地址
func Compress(files []*os.File, dest string) error {

	d, _ := os.Create(dest)
	defer d.Close()
	zipW := zip.NewWriter(d)
	defer zipW.Close()

	for _, file := range files {
		err := compress(file, "", zipW)
		if err != nil {
			println("压缩出错", err)
			return err
		}
	}
	return nil
}

func compress(file *os.File, prefix string, zw *zip.Writer) error {
	info, err := file.Stat()
	if err != nil {
		return err
	}
	if info.IsDir() {
		if len(prefix) == 0 {
			prefix = info.Name()
		} else {
			prefix = prefix + "/" + info.Name()
		}
		fileInfos, err := file.Readdir(-1)
		if err != nil {
			return err
		}
		for _, fi := range fileInfos {
			f, err := os.Open(file.Name() + "/" + fi.Name())
			if err != nil {
				return err
			}
			err = compress(f, prefix, zw)
			if err != nil {
				return err
			}
		}
	} else {
		header, err := zip.FileInfoHeader(info)
		if len(prefix) == 0 {
			header.Name = header.Name
		} else {
			header.Name = prefix + "/" + header.Name
		}
		if err != nil {
			return err
		}
		writer, err := zw.CreateHeader(header)
		if err != nil {
			return err
		}
		_, err = io.Copy(writer, file)
		file.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

// ImportData 导入数据
func ImportData() {

	timer2 := time.NewTimer(time.Second * 3)

	go func() {
		//等触发时的信号,阻塞线程
		<-timer2.C

		//先清空
		fmt.Println("开始清数据")
		db.DeleteAll("langItem")

		fmt.Println("开始导入数据")

		file, err := os.Open("./data.json")
		defer file.Close()
		if err != nil {
			fmt.Println("读取json出错")
			return
		}

		fd, err := ioutil.ReadAll(file)
		if err != nil {
			fmt.Println("json流读取出错")
			return
		}

		//1.先转成map
		var mapResult []interface{}
		merr := json.Unmarshal(fd, &mapResult)

		if merr == nil {
			suc := db.InsertBench(mapResult, "langItem")
			if !suc {
				fmt.Println("插入mongodb出错")
			} else {
				println("导入成功")
			}
		} else {
			fmt.Println("json序列化出错")
		}

	}()

}
